﻿#include <rapidxml/rapidxml.hpp>
#include "CameraImpl.h"

CameraImpl::CameraImpl(int iCamid, ProcessCallback process, EventCallback evt, void* pContext)
    : GCamera(iCamid, process, evt), m_pCallbakContext(pContext)
{
}

CameraImpl::~CameraImpl(void)
{
    if (m_bInit) {
        SetEvent(m_hEvtEnd);
        WaitForSingleObject(m_hRunThread, 30000);
        CloseHandle(m_hEvtTrigger);
        CloseHandle(m_hEvtEnd);
        CloseHandle(m_hRunThread);
    }
}

bool CameraImpl::Init()
{
    if (m_bInit) { return true; }
    wcscpy(m_LastError, L"ok");
    QByteArray content = ReadMainConfig();
    if (content.isEmpty()) { return false; }

    rapidxml::xml_document<> xDoc;
    xDoc.parse<0>(content.data());
    rapidxml::xml_node<>* xnCameraConfig = xDoc.first_node("system")->first_node("CameraConfig");
    Q_ASSERT(xnCameraConfig);
    for (auto attr = xnCameraConfig->first_attribute(); attr; attr = attr->next_attribute()) {
        qDebug() << QString(attr->name()) + " = " + attr->value();
    }

    rapidxml::xml_node<>* xnItem = nullptr;
    rapidxml::xml_node<>* xnStations = xnCameraConfig->first_node("Stations");
    for (auto s = xnStations->first_node("station"); s && !xnItem; s = s->next_sibling("station")) {
        for (auto camera = s->first_node("Item"); camera; camera = camera->next_sibling("Item")) {
            auto attribute = camera->first_attribute("id");
            if (attribute) {
                QString idItem = attribute->value();
                if (idItem.toInt() == GetCameraId()) {
                    xnItem = camera;
                    break;
                }
            }
        }
    }

    if (xnItem == 0) {
        wcscpy(m_LastError, L"配置文件异常，检查相机配置");
        return false;
    }

    auto attribute = xnItem->first_attribute("path");
    if (attribute == 0) {
        wcscpy(m_LastError, L"配置文件异常，检查path属性");
        return false;
    }
    QString path = attribute->value();
    if (path[1] != ':') {
        path = QCoreApplication::applicationDirPath() + "/" + path;
    }
    QDir localDir(path, "*.bmp");
    for (QFileInfo& ref : localDir.entryInfoList()) {
        m_filesList << ref.absoluteFilePath();
    }
    if (m_filesList.isEmpty()) {
        wcscpy(m_LastError, L"目标文件夹中无bmp图像。");
        return false;
    }
    for (int i = 0; i < MAX_LOAD && i < m_filesList.size(); i++) {
        m_imageLoaded[i].LoadBmp(m_filesList[i]);
    }

    QString str = QString("Virtual(%1x%2)=%3").arg(GetImageWidth()).arg(GetImageHeight()).arg(path);
    wcscpy(m_szDeviceName, str.toStdWString().c_str());
    m_hEvtTrigger = CreateEventA(NULL, TRUE, FALSE, QString("VirtualCamTriger%1").arg(GetCameraId()).toLatin1());
    m_hEvtEnd = CreateEventA(NULL, FALSE, FALSE, NULL);
    m_hRunThread = CreateThread(0, 0, GrabImageThread, this, 0, 0);
    return m_bInit = true;
}

const wchar_t* CameraImpl::GetDeviceName()
{
    return m_szDeviceName;
}

int CameraImpl::GetImageWidth()
{
    return m_imageLoaded[0].GetWidth();
}
int CameraImpl::GetImageHeight()
{
    return m_imageLoaded[0].GetHeight();
}
int CameraImpl::GetPixelBytes()
{
    return m_imageLoaded[0].IsGray() ? 1 : 4;
}

bool CameraImpl::SoftTrigger()
{
    if (m_bRunning) {
        SetEvent(m_hEvtTrigger);
    }
    return true;
}

QByteArray CameraImpl::ReadMainConfig()
{
    QByteArray content;
    QFile file(QCoreApplication::applicationDirPath() + "/config/system.xml");
    if (file.open(QIODevice::ReadOnly)) {
        content = file.readAll();
        file.close();
    }
    else {
        wcscpy(m_LastError, L"不能打开文件：system.xml");
    }
    return content;
}

DWORD WINAPI CameraImpl::GrabImageThread(LPVOID pParam)
{
    CameraImpl* pThis = (CameraImpl*)pParam;
    int iProcessCnt = 0, iProcessTotal = 0;
    HANDLE hMul[] = { pThis->m_hEvtTrigger, pThis->m_hEvtEnd };
    while (1) {
        DWORD nRet = WaitForMultipleObjects(2, hMul, FALSE, INFINITE);
        if (WAIT_OBJECT_0 == nRet && pThis->m_bRunning) {
            if (iProcessCnt < MAX_LOAD) {
                pThis->m_imageProcess.CopyImage(pThis->m_imageLoaded[iProcessCnt]);
            }
            else {
                pThis->m_imageProcess.LoadBmp(pThis->m_filesList[iProcessCnt]);
            }

            iProcessCnt = (iProcessCnt + 1) % pThis->m_filesList.size();
            if (pThis->m_imageProcess.GetWidth() == pThis->GetImageWidth() &&
                pThis->m_imageProcess.GetHeight() == pThis->GetImageHeight() &&
                pThis->m_imageProcess.IsGray() == (pThis->GetPixelBytes() == 1)) {
                pThis->Event(pThis->GetCameraId(), 36866, pThis->m_pCallbakContext);
                pThis->Process(pThis->GetCameraId(), pThis->m_imageProcess, pThis->m_pCallbakContext);
                qDebug() << "Process " << ++iProcessTotal << " images!";
            }
            else {
                continue;
            }
        }
        if (WAIT_OBJECT_0 + 1 == nRet) {
            break;
        }
        ResetEvent(pThis->m_hEvtTrigger);
    }
    return 0;
}
